//
//  BaseHistoryQueue.swift
//  MySwiftObject
//
//  Created by wangws1990 on 2021/1/11.
//  Copyright © 2021 wangws1990. All rights reserved.
//

import UIKit
import SQLite.Swift

private let BrowseTable    = "HistoryTable"

private let id             = Expression<String>("primaryId")
private let chapter        = Expression<Int>("chapter")
private let pageIndex      = Expression<Int>("pageIndex")
private let insertTime     = Expression<TimeInterval>("insertTime")
private let data           = Expression<Data?>("chapterDatas")
private let book           = Expression<String?>("bookInfo")
private let source         = Expression<String?>("source")

class BaseHistoryQueue :BaseConnection{
    fileprivate lazy var table: Table? = {
        guard let db = dataBase.db else { return nil }
        let tables = Table(BrowseTable)
        guard let _ = try? db.run(tables.create(ifNotExists: true, block: { (table) in
            //注意.autoincrement
            table.column(id,primaryKey: true)
            table.column(chapter)
            table.column(pageIndex)
            table.column(insertTime)
            
            table.column(data)
            table.column(book)
            table.column(source)
        })) else { return nil }
        return tables
    }()
    private func selectCount(tableName :String,primaryId :String) ->Int{
        guard let db = dataBase.db else { return 0 }
        guard let tb = table else { return 0 }
        let alice = tb.filter(id == primaryId)
        guard let count = try? db.scalar(alice.count) else { return 0 }
        return count
    }
    public func haveData(_ bookId :String) -> Bool{
        let count = selectCount(tableName: BrowseTable, primaryId: bookId)
        return count  > 0 ? true : false
    }
}
extension BaseHistoryQueue{
    public func insertData(bookId :String,chap :Int,page :Int,bookInfo:String?,chapDatas :Data?,sour :String?,completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let tb = self.table else { return completion(false) }
        let count = self.haveData(bookId)
        let time = Date().timeIntervalSince1970
        if !count{
            let insertdata = tb.insert(id <- bookId,
                                          chapter <- chap,
                                          pageIndex <- page,
                                          insertTime <- time,
                                          book <- bookInfo ?? "",
                                          data <- chapDatas ?? Data(),
                                          source <- sour ?? "")
            guard let _ = try? db.run(insertdata) else { return completion(false) }
            completion(true)
        }
    }
    public func updateChapData(bookId :String,chapData :Data?,completion:@escaping ((_ success : Bool) -> Void)){
        if self.haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,data <- chapData ?? Data() ,insertTime <- time)
            runUpdate(update, completion: completion)
        }else{
            self.insertData(bookId: bookId, chap: 0, page: 0, bookInfo: nil, chapDatas: chapData,sour: nil
                       , completion: completion)
        }
    }
    public func updateBook(bookId :String,bookInfo:String,completion:@escaping ((_ success : Bool) -> Void)){
        if self.haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,book <- bookInfo,insertTime <- time)
            runUpdate(update, completion: completion)
        }else{
            self.insertData(bookId: bookId, chap: 0, page: 0, bookInfo: bookInfo, chapDatas: nil,sour: nil
                       , completion: completion)
        }
    }
    public func  updateSource(bookId :String,sour :String,completion:@escaping ((_ success : Bool) -> Void)){
        if self.haveData(bookId){
            guard let tb = self.table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,insertTime <- time,source <- sour)
            runUpdate(update, completion: completion)
        }else{
            self.insertData(bookId: bookId, chap: 0, page: 0, bookInfo: nil, chapDatas: nil,sour: sour
                       , completion: completion)
        }
    }
    public func  updateChapterIndex(bookId :String,chap :Int,page :Int,completion:@escaping ((_ success : Bool) -> Void)){
        if self.haveData(bookId){
            let time = Date().timeIntervalSince1970
            guard let tb = self.table else { return completion(false) }
            let run = tb.filter(bookId == id)
            let update = run.update(id <- bookId,insertTime <- time,chapter <- chap,pageIndex <- page)
            runUpdate(update, completion: completion)
        }else{
            self.insertData(bookId: bookId, chap: chap, page: page, bookInfo: nil, chapDatas: nil,sour: nil
                       , completion: completion)
        }
    }

    public func deleteData(bookId :String,completion:@escaping ((_ success : Bool) -> Void)){
        guard let db = dataBase.db else { return completion(false) }
        guard let tb = self.table else { return completion(false) }
        let alice = tb.filter(id == bookId)
        guard let _ = try? db.run(alice.delete()) else { return completion(false) }
        completion(true)
    }
    public func getData(bookId :String,needChapter :Bool,completion:@escaping ((_ model : GKHistory?) -> Void)){
        guard let db = dataBase.db else { return completion(nil) }
        guard let tb = self.table else { return completion(nil) }
        let alice = tb.filter(id == bookId)
        guard let datas : AnySequence<Row> = try? db.prepare(alice) else {
            return completion(nil)
        }
        let objc = datas.first { row in
            return String(row[id]).count > 0
        }
        guard let row = objc else {
            return completion(nil)
        }
        let his = decode(objc: row, needChapter: needChapter)
        completion(his)
    }
    public func getData(page : Int,size : Int = 20,completion:@escaping ((_ datas : [GKHistory]) ->())){
        guard let db = dataBase.db else { return completion([]) }
        guard let tb = self.table else { return completion([]) }
        let order = tb.order(insertTime.desc).limit(size, offset: (page - 1) * size)
        guard let datas : AnySequence<Row> = try? db.prepare(order) else {
            return completion([])
        }
        decodeData(listData: datas,needChapter: false,completion: completion)
    }
    public func getData(completion:@escaping ((_ datas : [GKHistory]) ->())){
        guard let db = dataBase.db else { return completion([]) }
        guard let tb = self.table else { return completion([]) }
        let order = tb.order(insertTime.desc)
        guard let datas : AnySequence<Row> = try? db.prepare(order) else {
            return completion([])
        }
        decodeData(listData: datas,needChapter: false,completion: completion)
    }
    private func decodeData(listData : AnySequence<Row>,needChapter :Bool = false,completion:@escaping ((_ datas : [GKHistory]) ->Void)){
        DispatchQueue.global().async {
            var content : [GKHistory] = []
            listData.forEach { (objc) in
                if let model = self.decode(objc: objc, needChapter: needChapter){
                    content.append(model)
                }
            }
            DispatchQueue.main.async {
                completion(content)
            }
        }
    }
    private func decode(objc : Row,needChapter :Bool) -> GKHistory?{
        let  model =  GKHistory()
        if let bookId = try? objc.get(id) {
            model.bookId = bookId
        }
        if let chap = try? objc.get(chapter) {
            model.chapter = chap
        }
        if let page = try? objc.get(pageIndex) {
            model.pageIndex = page
        }
        if let time = try? objc.get(insertTime){
            model.insertTime =  TimeInterval(time)
        }
        if let json = try? objc.get(book) {
            let bookJson = JSON(parseJSON:json)
            let info = GKBook.deserialize(from: bookJson.rawString())
            model.book = info
        }
        if let json = try? objc.get(source) {
            let bookJson = JSON(parseJSON:json)
            let info = GKSource.deserialize(from: bookJson.rawString())
            model.source = info
        }
        if needChapter {
            if let str = try? objc.get(data) {
                if str.count > 0{
                    let json = JSON(str)
                    model.chapters = json.array
                }
            }
        }
        return model
    }
    fileprivate func runUpdate(_ task :Update,completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let _ = try? db.run(task) else { return completion(false) }
        completion(true)
    }
}
